package com.eastdigit.servlet;

import com.eastdigit.system.model.BusinessException;
import com.eastdigit.system.service.IFieldAliasService;
import com.eastdigit.system.service.SpringServiceFactory;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by hehz on 2016/7/15.
 */
@Aspect
@Component
public class FieldAliasAspect {

    /**
     * 添加字段别名
     * 
     * @param joinPoint
     * @param returnVal
     */
    @AfterReturning(pointcut = "@annotation(com.eastdigit.servlet.FieldAlias)", returning = "returnVal")
    public void afterReturning(JoinPoint joinPoint, Object returnVal) {
        FieldAlias fieldAlias = (FieldAlias) getMethodAnnotation(joinPoint, FieldAlias.class);
        if (fieldAlias != null && (returnVal instanceof JSONObject || returnVal instanceof JSONArray)) {
            dealFieldAliases(new FieldAlias[] { fieldAlias }, returnVal);
        }
    }

    /**
     * 添加字段别名
     * 
     * @param joinPoint
     * @param returnVal
     */
    @AfterReturning(pointcut = "@annotation(com.eastdigit.servlet.FieldAliases)", returning = "returnVal")
    public void afterReturnings(JoinPoint joinPoint, Object returnVal) {
        FieldAliases fieldAliases = (FieldAliases) getMethodAnnotation(joinPoint, FieldAliases.class);
        if (fieldAliases != null && (returnVal instanceof JSONObject || returnVal instanceof JSONArray)) {
            dealFieldAliases(fieldAliases.value(), returnVal);
        }
    }

    private void dealFieldAliases(FieldAlias[] fieldAliases, Object data) {
        List<JSONObject> list = new ArrayList<JSONObject>();
        Map<String, List<Object>> filedMap = new HashMap<String, List<Object>>();

        if (data instanceof JSONObject && !((JSONObject) data).containsKey("rows")) {
            JSONObject json = (JSONObject) data;
            for (FieldAlias fieldAlias : fieldAliases) {
                String field = fieldAlias.field();
                if (json.containsKey(field)) {
                    List<Object> fileds = filedMap.get(fieldAlias.service());
                    if (fileds == null) {
                        fileds = new ArrayList<Object>();
                        filedMap.put(fieldAlias.service(), fileds);
                    }
                    list.add(json);
                    fileds.add(json.getString(field));
                }
            }
        } else {
            JSONArray rows = null;
            if (data instanceof JSONArray) {
                rows = ((JSONArray) data);
            } else {
                rows = ((JSONObject) data).optJSONArray("rows");
            }
            if (rows != null && rows.size() > 0) {
                for (int i = 0; i < rows.size(); i++) {
                    JSONObject json = rows.getJSONObject(i);
                    for (FieldAlias fieldAlias : fieldAliases) {
                        String field = fieldAlias.field();
                        if (json.containsKey(field)) {
                            String key = fieldAlias.service() + "|" + fieldAlias.param();
                            List<Object> fileds = filedMap.get(key);
                            if (fileds == null) {
                                fileds = new ArrayList<Object>();
                                filedMap.put(key, fileds);
                            }
                            list.add(json);
                            fileds.add(json.getString(field));
                        }
                    }
                }
            }
            if (filedMap.size() > 0) {
                Map<String, Map<String, Object>> valueMap = new HashMap<String, Map<String, Object>>();
                for (String key : filedMap.keySet()) {
                    String[] arr = key.split("\\|");
                    Map<String, Object> map = getFieldAliasService(arr[0]).dealFieldAlias(filedMap.get(key),
                            arr.length == 2 ? arr[1] : null);
                    valueMap.put(key, map);
                }

                for (JSONObject jsonObject : list) {
                    for (FieldAlias fieldAlias : fieldAliases) {
                        String field = fieldAlias.field(), alias = fieldAlias.alias();
                        Object value = jsonObject.getString(field), aliasValue = valueMap.get(
                                fieldAlias.service() + "|" + fieldAlias.param()).get(value);
                        if (aliasValue == null) {
                            aliasValue = value;
                        }
                        jsonObject.put(alias, aliasValue);
                    }
                }
            }
        }
    }

    /**
     * 获取方法Annotation
     * 
     * @param joinPoint
     * @param clazz
     * @return
     */
    private Annotation getMethodAnnotation(JoinPoint joinPoint, Class clazz) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Class[] argClasses = null;
        if (args != null) {
            argClasses = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                argClasses[i] = args[i].getClass();
            }
        }
        try {
            return joinPoint.getTarget().getClass().getMethod(methodName, argClasses).getAnnotation(clazz);
        } catch (NoSuchMethodException e) {

        }
        return null;
    }

    protected IFieldAliasService getFieldAliasService(String serviceName) {
        IFieldAliasService service = SpringServiceFactory.getInstance(serviceName, IFieldAliasService.class);
        if (service == null) {
            throw new BusinessException("获取服务" + serviceName + "失败！");
        }
        return service;
    }
}
